﻿using HarmonyLib;
using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Verse;
using Verse.AI;
using Verse.Noise;
using static HarmonyLib.Code;

namespace Meow
{
    public class CompProperties_ThingCarrier : CompProperties
    {
        public Vector3 eastOffset;
        public Vector3 westOffset;
        public Vector3 southOffset;
        public Vector3 northOffset;

        public float bodySizeBase = 1;
        public float bodySizeScaleFactor = 1;


        public CompProperties_ThingCarrier()
        {
            compClass = typeof(Comp_ThingCarrier);
        }
    }
    
    [StaticConstructorOnStartup]
    public class Comp_ThingCarrier : ThingComp
    {
        public Pawn Self;
        public Pawn Carrying;

        public float OffsetScale = 1;

        public CompProperties_ThingCarrier Props;

        public static Dictionary<Thing, Comp_ThingCarrier> CarryingOffset = new Dictionary<Thing, Comp_ThingCarrier>();



        public override void Initialize(CompProperties props)
        {
            base.Initialize(props);
            Self = parent as Pawn;
            Props = props as CompProperties_ThingCarrier;
        }

        public void Carry(Pawn toCarry)
        {
            if (Carrying != null)
            {
                CarryingOffset.Remove(Carrying);
                Carrying.Position = Self.Position;
                Carrying.Rotation = Self.Rotation;
                Carrying.Drawer.tweener = new PawnTweener(Carrying);
            }

            Carrying = toCarry;

            if (toCarry != null)
            {
                CarryingOffset[toCarry] = this;

                Carrying.Position = Self.Position;
                Carrying.Rotation = Self.Rotation;
                Carrying.Drawer.tweener = Self.Drawer.tweener;
            }
        }

        public override void CompTick()
        {
            base.CompTick();

            if (Self.Spawned && Carrying != null)
            {
                Carrying.Position = Self.Position;
                Carrying.Rotation = Self.Rotation;
                Carrying.Drawer.tweener = Self.Drawer.tweener;

                OffsetScale = (Self.BodySize - Props.bodySizeBase) * Props.bodySizeScaleFactor;

                if (Carrying.Destroyed || Carrying.Dead || Carrying.Downed || Carrying.InMentalState)
                {
                    Carry(null);
                }
            }
        }

        public override void PostExposeData()
        {
            base.PostExposeData();
            Scribe_References.Look(ref Carrying, "Carrying");
        }
    }

    
    public class PawnRenderOffsetPatch
    {

        [HarmonyPatch(typeof(PawnRenderer), "ParallelGetPreRenderResults")]
        public class PawnRenderPatch_ParallelGetPreRenderResults
        {
            [HarmonyPrefix]
            public static void ChangeOffset(PawnRenderer __instance, ref Vector3 drawLoc, Rot4? rotOverride = null)
            {
                var pr = Traverse.Create(__instance);
                var pawn = (Pawn)(pr.Field("pawn").GetValue());

                PawnRenderFlags pawnRenderFlags = PawnRenderFlags.None;
                if (!pawn.health.hediffSet.HasHead)
                {
                    pawnRenderFlags |= PawnRenderFlags.HeadStump;
                }
                if (pawnRenderFlags.FlagSet(PawnRenderFlags.Portrait))
                {
                    return;
                }

                if (Comp_ThingCarrier.CarryingOffset.TryGetValue(pawn, out var comps))
                {
                    Rot4 rot = rotOverride ?? pawn.Rotation;
                    var offset = Vector3.zero;
                    switch (rot.AsInt)
                    {
                        case 0: offset = comps.Props.northOffset; break; // North
                        case 1: offset = comps.Props.eastOffset; break; // East
                        case 2: offset = comps.Props.southOffset; break; // South
                        case 3: offset = comps.Props.westOffset; break; // West
                    }
                    offset *= comps.OffsetScale;
                    drawLoc += offset;
                }
            }

        }

    }


}
